/* eslint-disable @typescript-eslint/no-explicit-any */
import axios from 'axios'

import type { AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
import type { XBRequestConfig } from './type'

// 拦截器：蒙版Loading/token/修改配置

/**
 * 两个难点:
 * 1. 拦截器进行精细控制
 *   > 全局拦截器
 *   > 实例拦截器
 *   > 单次请求拦截器
 * 2. 响应结果的类型处理（泛型）
 */

class XBRequest {
  instance: AxiosInstance

  // request实例 => axios的实例
  constructor(config: XBRequestConfig) {
    this.instance = axios.create(config)

    // 每个instance实例都添加拦截器
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        // Loading/token
        // console.log('全局请求成功的拦截')
        return config
      },
      (err) => {
        // console.log('全局请求失败的拦截')
        return err
      },
    )
    this.instance.interceptors.response.use(
      (res: AxiosResponse) => {
        // console.log('全局响应成功的拦截')
        return res.data
      },
      (err) => {
        // console.log('全局响应失败的拦截')
        return err
      },
    )

    // 局部拦截器
    this.instance.interceptors.request.use(config.interceptors?.requestSuccessFn, config.interceptors?.requestFailureFn)
    this.instance.interceptors.response.use(config.interceptors?.responseSuccessFn, config.interceptors?.responseFailureFn)
  }

  // 单个请求拦截器
  request<T = any>(config: XBRequestConfig<T>) {
    // if (config?.interceptors) {
    //   this.instance.interceptors.request.use(config.interceptors?.requestSuccessFn, config.interceptors?.requestFailureFn)
    //   this.instance.interceptors.response.use(config.interceptors?.responseSuccessFn, config.interceptors?.responseFailureFn)
    // }

    // 返回Promise
    return new Promise<T>((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res) => {
          if (config.interceptors?.responseSuccessFn) {
            res = config.interceptors.responseSuccessFn(res)
          }

          resolve(res)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }

  get<T = any>(config: XBRequestConfig<T>) {
    return this.request({ ...config, method: 'GET' })
  }

  post<T = any>(config: XBRequestConfig<T>) {
    return this.request({ ...config, method: 'POST' })
  }

  delete<T = any>(config: XBRequestConfig<T>) {
    return this.request({ ...config, method: 'DELETE' })
  }

  patch<T = any>(config: XBRequestConfig<T>) {
    return this.request({ ...config, method: 'PATCH' })
  }
}

export default XBRequest
